#include "FaceDetectorModule.h"
#include <sstream>
#include <iostream>
#include "cv.h"
using namespace std;
using namespace cv;
/*******************************************************************/
CFaceDetectorModule::CFaceDetectorModule(void)
{
	m_storage = cvCreateMemStorage(0);
	m_size = cvSize(800,600);
	m_scale = 1;
	m_colors.push_back(CV_RGB(255,0,0));
	m_colors.push_back(CV_RGB(0,255,0));
	m_colors.push_back(CV_RGB(0,0,255));
	m_colors.push_back(CV_RGB(255,255,0));
	m_colors.push_back(CV_RGB(255,0,255));
	m_colors.push_back(CV_RGB(0,255,255));
	m_colors.push_back(CV_RGB(255,255,255));
}
/*******************************************************************/
CFaceDetectorModule::~CFaceDetectorModule(void)
{
	if( NULL != m_storage )
	{
		cvReleaseMemStorage(&m_storage);
	}
	std::map<string, CvHaarClassifierCascade*>::iterator iter;
	for( iter = m_detectors.begin(); iter != m_detectors.end(); ++iter )
	{
		CvHaarClassifierCascade * temp=NULL;
		temp = iter->second;
		if( NULL != temp )
		{
			delete temp;
		}
	}
}
/*******************************************************************/
bool CFaceDetectorModule::InitializeHaarDetectors( string path, vector<string> cascades, vector<string> names )
{
	bool retVal = false;
	if( names.size()==cascades.size() )
	{
		int size = static_cast<int>(cascades.size());
		int count = 0;
		int n_colors = static_cast<int>(m_colors.size());
		for( int i=0; i<size; ++i)
		{
			CvHaarClassifierCascade* temp=NULL;
			ostringstream fullName;
			fullName << path << cascades[i];
			temp = cvLoadHaarClassifierCascade(fullName.str().c_str(), m_size );
			if( NULL != temp )
			{
				m_colorMap[names[i]]=m_colors[i%n_colors];
				m_detectors[names[i]]=temp;
				count++;
			}
		}
		if( count == size )
			retVal = true;
	}
	return retVal; 
}
/*******************************************************************/
TFaceList CFaceDetectorModule::DetectFaces( IplImage * img )
{
	TFaceList retVal;
	if( NULL != img && m_detectors.size() > 0 )
	{
		IplImage* temp = cvCreateImage( cvSize(img->width/m_scale,img->height/m_scale), 8, 3 );
		cvResize(img,temp);
		std::map<string, CvHaarClassifierCascade*>::iterator iter;
		for( iter = m_detectors.begin(); iter != m_detectors.end(); ++iter )
		{
			
  			CvSeq* faces = cvHaarDetectObjects( temp, iter->second, m_storage );
			for( int i = 0; i < (faces ? faces->total : 0); i++ )
			{
				// Create a new rectangle for drawing the face
				CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
		        // Find the dimensions of the face,and scale it if necessary
			    SFaceObject facePos;
				facePos.m_pt1.x = r->x*m_scale;
				facePos.m_pt2.x = (r->x+r->width)*m_scale;
			    facePos.m_pt1.y = r->y*m_scale;
				facePos.m_pt2.y = (r->y+r->height)*m_scale;
				facePos.m_face.width = r->width*m_scale;
				facePos.m_face.height = r->height*m_scale;
				facePos.m_face.x = r->x*m_scale;
				facePos.m_face.y = r->y*m_scale;
				facePos.m_type = iter->first;
				retVal.push_back(facePos);
			}
			cvClearMemStorage( m_storage );

		}
		
		cvReleaseImage( &temp );
	}
	return retVal; 
}

/*******************************************************************/
SFaceObject CFaceDetectorModule::GetBiggestFace( IplImage * img )
{
	TFaceList faces = DetectFaces( img );
	SFaceObject retVal;

	int sz = static_cast<int>(faces.size()); 
	int index=-1;
	int fsz=0;
	for( int i=0; i < sz; i++ )
	{
		int tsz = faces[i].m_face.width*faces[i].m_face.height; 
		if( tsz > fsz )
		{
			tsz = fsz;
			index = i;
		}
	}
	if( index > -1 )
	{
		retVal = faces[index];
	//	cvRectangle( img, retVal.m_pt1, retVal.m_pt2, m_colorMap[retVal.m_type], 3, 8, 0 );
	}
	return retVal;
}
/*******************************************************************/
TFaceList CFaceDetectorModule::DetectAndDrawFaces( IplImage * img ) 
{
	TFaceList retVal = DetectFaces(img);
	DrawFaces(img, retVal);
	return retVal;
}
/*******************************************************************/
void CFaceDetectorModule::DrawFaces( IplImage* img, TFaceList faces)
{
	if( NULL != img )
	{	
		TFaceListIter iter;
		for( iter = faces.begin(); iter < faces.end(); ++iter )
		{
			cvRectangle( img, iter->m_pt1, iter->m_pt2, m_colorMap[iter->m_type], 3, 8, 0 );
		}
	}
}
/*******************************************************************/
void CFaceDetectorModule::SetScale( int scale )
{
	m_scale = scale;
}
/*******************************************************************/
int  CFaceDetectorModule::GetScale( void )
{
	return m_scale;
}
/*******************************************************************/
void CFaceDetectorModule::DrawFace( IplImage* img, SFaceObject face )
{
	cvRectangle( img, face.m_pt1, face.m_pt2, m_colorMap[face.m_type], 3, 8, 0 );
}
/*******************************************************************/